package cn.rokhdelar.umbrsapi.core.jpa;

import jakarta.persistence.criteria.*;
import org.springframework.data.domain.Sort;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * 根据PARAMETER中传入条件并进行解析
 *
 */
public class ParameterParser {
	
	public static final String SPLIT = "_";

	public void addCriterion( CriteriaBuilder builder, CriteriaQuery<?> countQuery, Root<?> root, FilterMap filterMap, Sort sort) {
		if (filterMap != null && !filterMap.isEmpty()) {
			List<Predicate> predicates = new ArrayList<>(); // 使用列表来收集多个条件
			for (String key : filterMap.keySet()) {
				String[] pt = key.split(SPLIT);
				String propertyName = pt[0];
				String type = pt[1];
				Object value = filterMap.get(key);
				Path<?> propertyPath = root.get(propertyName); // 获取属性路径
				Predicate predicate = builder.conjunction();
				if (type.equals(CriteriaConstant.EQ)) {
					Predicate eq = builder.equal(propertyPath,value);
					predicates.add(eq);
				} else if (type.equals(CriteriaConstant.NE)) {
					Predicate notEqual = builder.notEqual(propertyPath,value);
					predicates.add(notEqual);
				} else if (type.equals(CriteriaConstant.GT)) {
					if (value instanceof Number) {
						Number numberValue = (Number) value;

						Predicate gt = builder.gt(propertyPath.as(Long.class), numberValue.longValue());
						predicates.add(gt);

					} else if (value instanceof LocalDate) {

						LocalDate dateValue = (LocalDate) value;
						Predicate greaterThan = builder.greaterThan(propertyPath.as(LocalDate.class), dateValue);
						predicates.add(greaterThan);

					} else if (value instanceof LocalDateTime) {
						LocalDateTime dateTimeValue = (LocalDateTime) value;
						Predicate greaterThan = builder.greaterThan(propertyPath.as(LocalDateTime.class), dateTimeValue);
						predicates.add(greaterThan);
					}
				}else if (type.equals(CriteriaConstant.GE)) {
					if (value instanceof Number) {
						Number numberValue = (Number) value;

						Predicate ge = builder.ge(propertyPath.as(Long.class), numberValue.longValue());
						predicates.add(ge);

					} else if (value instanceof LocalDate) {
						LocalDate dateValue = (LocalDate) value;
						Predicate greaterThanOrEqualTo = builder.greaterThanOrEqualTo(propertyPath.as(LocalDate.class), dateValue);
						predicates.add(greaterThanOrEqualTo);

					} else if (value instanceof LocalDateTime) {
						LocalDateTime dateTimeValue = (LocalDateTime) value;
						Predicate greaterThanOrEqualTo = builder.greaterThanOrEqualTo(propertyPath.as(LocalDateTime.class), dateTimeValue);
						predicates.add(greaterThanOrEqualTo);
					}
				}else if (type.equals(CriteriaConstant.LT)) {
					if (value instanceof Number) {
						Number numberValue = (Number) value;
						Predicate lt = builder.lt(propertyPath.as(Long.class), numberValue.longValue());
						predicates.add(lt);

					} else if (value instanceof LocalDate) {
						LocalDate dateValue = (LocalDate) value;
						Predicate lessThan = builder.lessThan(propertyPath.as(LocalDate.class), dateValue);
						predicates.add(lessThan);

					}else if (value instanceof LocalDateTime) {
						LocalDateTime dateTimeValue = (LocalDateTime) value;
						Predicate lessThan = builder.lessThan(propertyPath.as(LocalDateTime.class), dateTimeValue);
						predicates.add(lessThan);
					}
				}else if (type.equals(CriteriaConstant.LE)) {
					if (value instanceof Number) {

						Number numberValue = (Number) value;
						Predicate le = builder.le(propertyPath.as(Long.class), numberValue.longValue());
						predicates.add(le);

					} else if (value instanceof LocalDate) {
						LocalDate dateValue = (LocalDate) value;

						Predicate lessThanOrEqualTo = builder.lessThanOrEqualTo(propertyPath.as(LocalDate.class), dateValue);
						predicates.add(lessThanOrEqualTo);

					} else if (value instanceof LocalDateTime) {
						LocalDateTime dateValue = (LocalDateTime) value;
						Predicate lessThanOrEqualTo = builder.lessThanOrEqualTo(propertyPath.as(LocalDateTime.class), dateValue);
						predicates.add(lessThanOrEqualTo);
					}
				}else if (type.equals(CriteriaConstant.BETWEEN)) {
					Map<String, Object> map =(Map<String, Object>) value;
					Object minValue =  map.get(CriteriaConstant.LO);
					Object maxValue = map.get(CriteriaConstant.HI);
					if (minValue instanceof Number && maxValue instanceof Number) {
						Number numberminValue = (Number) minValue;
						Number numbermaxValue = (Number) maxValue;
						Predicate between = builder.between(propertyPath.as(Long.class), numberminValue.longValue(), numbermaxValue.longValue());
						predicates.add(between);

					} else if (minValue instanceof LocalDate && maxValue instanceof LocalDate) {
						LocalDate dateMinValue = (LocalDate) minValue;
						LocalDate dateMaxValue = (LocalDate) maxValue;

						Predicate between = builder.between(propertyPath.as(LocalDate.class), dateMinValue,dateMaxValue);
						predicates.add(between);

					}else if (minValue instanceof LocalDateTime && maxValue instanceof LocalDateTime) {

						LocalDateTime dateMinValue = (LocalDateTime) minValue;
						LocalDateTime dateMaxValue = (LocalDateTime) maxValue;

						Predicate between = builder.between(propertyPath.as(LocalDateTime.class), dateMinValue,dateMaxValue);
						predicates.add(between);


					}
				}else if (type.equals(CriteriaConstant.LIKE)) {
					Object[] valuev=(Object[])value;
					Predicate like = builder.like(root.get(propertyName), ((Object[])valuev[0])[0].toString());
					predicates.add(like);
				}else if(type.equals(CriteriaConstant.IN)){
					Object[] valuesArray = (Object[]) value;
					List<Object> valuesList= Arrays.asList(valuesArray);
					Predicate inPredicate = propertyPath.in(valuesList);
					predicates.add(inPredicate);

				}else if (type.equals(CriteriaConstant.NOTIN)) {
					Object[] valuesArray = (Object[]) value;
					List<Object> valuesList= Arrays.asList(valuesArray);
					Predicate notInPredicate =  builder.not(propertyPath.in(valuesList));
					predicates.add(notInPredicate);

				}else if (type.equals(CriteriaConstant.ISNULL)) {

					Predicate isNull = builder.isNull(propertyPath);
					predicates.add(isNull);

				}else if (type.equals(CriteriaConstant.ISNOTNULL)) {

					Predicate isNull = builder.isNotNull(propertyPath);
					predicates.add(isNull);

				}else if (type.equals(CriteriaConstant.ISEMPTY)) {
					Predicate isEmpty = builder.isEmpty(root.get(propertyName));
					predicates.add(isEmpty);
				}else if (type.equals(CriteriaConstant.ISNOTEMPTY)) {
					Predicate isNotEmpty = builder.isNotEmpty(root.get(propertyName));
					predicates.add(isNotEmpty);
				}else if (type.equals(CriteriaConstant.OR)) {
					FilterMap orFilterMap = (FilterMap) value;
					List<Predicate> orPredicates = new ArrayList<>();
					// 假设 FilterMap 有一个方法来获取所有的过滤条件
					for (String keyor : orFilterMap.keySet()) {
						String[] ptor = keyor.split(SPLIT);
						String propertyNameor = ptor[0];
						Object valueor = orFilterMap.get(keyor);
						Path<?> propertyPathor = root.get(propertyNameor); // 获取属性路径
						// 这里我们假设每个过滤条件都是等值条件，您可以根据实际情况进行调整
						Predicate orpredicate = builder.equal(propertyPathor, valueor);
						orPredicates.add(orpredicate);
					}
					// 将所有的 Predicate 组合成一个 OR 条件
					Predicate orPredicate = builder.or(orPredicates.toArray(new Predicate[0]));
					predicates.add(orPredicate); // 将 OR 谓词添加到主谓词列表中
				}

			}
			Predicate finalPredicate = builder.and(predicates.toArray(new Predicate[0])); // 使用所有收集的条件
			countQuery.where(finalPredicate);
		}
		if (sort != null) {
			for (Sort.Order order : sort) {
				// 动态获取排序字段的Path
				Path<?> propertyPath = root.get(order.getProperty());
				countQuery.orderBy(order.isAscending() ? builder.asc(propertyPath) : builder.desc(propertyPath));
			}
		}
	}


	
}
